// 1/异步工作器：
// 异步工作使用双缓冲区思想
// 外界将任务数据，添加到输入缓冲区中，
// 异步线程对处理缓冲区中的数据进行处理，若处理缓冲区中没有数据了则交换缓冲区
// 实现：
// 2/管理的成员：
// 双缓冲区（生产，消费）
// 互斥锁 // 保证线程安全
// 条件变量 - 生产 & 消费（生产缓冲区没有数据，处理完消费缓冲区数据后就休眠）
// 回调函数（针对缓冲区中数据的处理接口 - 外界传入一个函数，告诉异步工作器数据该如何处理）
// 3/提供的操作：
// 停止异步工作器
// 添加数据到缓冲区
// 私有操作：
// 创建线程，线程入口函数中，交换缓冲区，对消费缓冲区数据使用回调函数进行处理，处理完后再次交换
#ifndef __LOOPER_H__
#define __LOOPER_H__
#include <functional>
#include "util.hpp"
#include"buffer.hpp"
#include <atomic>
#include <thread>
#include<condition_variable>
// 其实异步工作线程应该有两种模式：
// 一种是安全模式：如果异步缓冲区数据满了就阻塞，等待处理完成之后交换缓冲区再继续处理（避免峰值模式下资源耗尽的风险）。
// 另一种是非安全模式：尽管往内存里去扩容放数据，不考虑内存情况，用来测试极限压力。
namespace logsys {
// 定义一个函数类型别名，该函数接受一个Buffer的引用且无返回值，用于处理缓冲区数据
using Functor = std::function<void(Buffer &)>; 

// 定义异步模式枚举类型
enum class AsyncType {
    ASYNC_SAFE,   // 安全状态，表示缓冲区满了则阻塞，避免资源耗尽的风险
    ASYNC_UNSAFE  // 不安全状态，不考虑资源耗尽的问题，无限扩容，常用于测试
};

class AsyncLooper {
public:
    // 定义智能指针类型，方便管理AsyncLooper对象
    using ptr = std::shared_ptr<AsyncLooper>; 

    // 构造函数，接收一个回调函数和异步模式参数，初始化停止标志为false
    // 并启动一个新线程，线程入口函数为threadEntry，传入当前对象指针
    AsyncLooper(const Functor &cb, AsyncType loop_type = AsyncType::ASYNC_SAFE) : 
        _stop(false),
        _looper_type(loop_type),
        _thread(std::thread(&AsyncLooper::threadEntry, this)),
        _callBack(cb) {} 

    // 析构函数，调用stop函数停止异步工作器
    ~AsyncLooper() { stop(); } 

    // 停止异步工作器的函数
    void stop() {
        _stop = true; // 设置停止标志为true
        _cond_con.notify_all(); // 唤醒所有工作线程
        _thread.join(); // 等待工作线程退出
    }

    // 向缓冲区添加数据的函数
    void push(const char *data, size_t len) {
        // 加锁，保证线程安全
        std::unique_lock<std::mutex> lock(_mutex); 
        // 根据异步模式判断是否需要等待缓冲区有足够空间
        if (_looper_type == AsyncType::ASYNC_SAFE) {
            _cond_pro.wait(lock, [&]{ return _pro_buf.writeAbleSize() >= len; }); 
        }
        // 满足条件后，向生产缓冲区添加数据
        _pro_buf.push(data, len); 
        // 根据异步模式判断是否唤醒生产者
        if (_looper_type == AsyncType::ASYNC_SAFE) {
            _cond_pro.notify_all(); 
        }
        // 唤醒消费者线程处理缓冲区数据
        _cond_con.notify_one(); 
    }

private:
    // 线程入口函数，处理消费缓冲区中的数据
    void threadEntry() {
        while (1) {
            // 加锁，管理缓冲区交换操作的线程安全
            std::unique_lock<std::mutex> lock(_mutex); 
            //防止我们写入缓冲区后程序退出stop被设计 一些缓冲区数据没写完
            if(_stop&&_pro_buf.empty()) break;
            // 防止缓冲区数据还没写完，程序就退出了（stop被设计在一些缓冲区数据没写完成时执行
            // 等待条件变量，直到生产缓冲区有数据或者工作器停止
            _cond_con.wait(lock, [&]{ return _stop ||!_pro_buf.empty(); }); 
            // 交换生产缓冲区和消费缓冲区
            _pro_buf.swap(_con_buf); 
            // 根据异步模式判断是否唤醒生产者
            if (_looper_type == AsyncType::ASYNC_SAFE) {
                _cond_pro.notify_all(); 
            }
            // 调用回调函数处理消费缓冲区中的数据
            _callBack(_con_buf); 
            // 初始化消费缓冲区
            _con_buf.reset(); 
        }
    }

private:
    Functor _callBack; // 具体对缓冲区数据进行处理的回调函数，由异步工作器使用者传入
private:
    std::atomic<bool> _stop; // 工作器停止标志
    AsyncType _looper_type; // 异步工作器模式
    Buffer _pro_buf; // 生产缓冲区
    Buffer _con_buf; // 消费缓冲区
    std::mutex _mutex; // 互斥锁，保证线程安全
    std::condition_variable _cond_pro; // 条件变量，用于生产者相关操作
    std::condition_variable _cond_con; // 条件变量，用于消费者相关操作
    std::thread _thread; // 异步工作器对应的工作线程
};
}
#endif